#include "BlockQueue.hpp"
#include "Task.hpp"
#include <sys/types.h>
#include <unistd.h>
#include <ctime>

// 想要实现的功能： 生产者生产数据 消费者消费数据
// 生产者随机生成数字以及运算符 消费者得出结果并返回

// C:计算
// S:存储

template <class C, class S>
class BlockQueues
{
public:
    BlockQueue<C> *c_bq;
    BlockQueue<S> *s_bq;
};
// 生产数据(生产者)
void *productor(void *bqs_)
{
    BlockQueue<CalTask> *bq = (static_cast<BlockQueues<CalTask, SaveTask> *>(bqs_))->c_bq;

    while (true)
    {
        sleep(5);
        int x = rand() % 100 + 1; // 用随机数构建数据
        int y = rand() % 10;
        int operCode = rand() % oper.size();
        // 传入的参数在Task.hpp当中都有定义
        CalTask t(x, y, oper[operCode], mymath);

        // 将任务插入生产队列
        bq->push(t);
        std::cout << "productor thread,生产计算任务: " << t.toTaskString() << std::endl;
    }
    return nullptr;
}
// 计算数据并提交数据 (消费者+生产者)
void *consumer(void *bqs_)
{
    BlockQueue<CalTask> *bq = (static_cast<BlockQueues<CalTask, SaveTask> *>(bqs_))->c_bq;
    BlockQueue<SaveTask> *save_bq = (static_cast<BlockQueues<CalTask, SaveTask> *>(bqs_))->s_bq;

    while(true)
    {
        // 消费活动
        CalTask t;
        bq->pop(&t);

        std::string result = t();
        std::cout << "cal thread,完成计算任务: " << result << "... done" << std::endl;
    
        SaveTask save(result,Save);
        save_bq->push(save);
        std::cout << "cal thread,推送保存任务完成..." << std::endl;

        sleep(1);
    }
    return nullptr;
}
// 保存数据(消费者)
void *saver(void *bqs_)
{
    BlockQueue<SaveTask> *save_bq = (static_cast<BlockQueues<CalTask, SaveTask> *>(bqs_))->s_bq;

    while(true)
    {
        SaveTask t;
        save_bq->pop(&t);
        t();
        std::cout << "save thread，保存任务完成..." << std::endl; 
    }
    return nullptr;
}

int main()
{
    // srand 随机数种子 通篇只需要设置1次 ^ getpid 伪随机 确保每次的随机性
    srand((unsigned long)time(nullptr) ^ getpid());

    BlockQueues<CalTask, SaveTask> bqs;
    // 创建计算和保存队列
    bqs.c_bq = new BlockQueue<CalTask>();
    bqs.s_bq = new BlockQueue<SaveTask>();

    // 创建2个生产者，2个消费者线程
    pthread_t c[2], p[2], s;
    pthread_create(p, nullptr, productor, &bqs);
    pthread_create(p + 1, nullptr, productor, &bqs);
    // pthread_create(p + 2, nullptr, productor, &bqs);
    sleep(1);
    pthread_create(c, nullptr, consumer, &bqs);
    pthread_create(c + 1, nullptr, consumer, &bqs);

    // 创建1个保存线程
    pthread_create(&s, nullptr, saver, &bqs);

    pthread_join(c[0], nullptr);
    pthread_join(c[1], nullptr);
    pthread_join(p[0], nullptr);
    pthread_join(p[1], nullptr);
    pthread_join(p[2], nullptr);
    pthread_join(s, nullptr);

    delete bqs.c_bq;
    delete bqs.s_bq;
    return 0;
}